#if defined(_MSC_VER)
#include "SDL.h"
#else
#include "SDL/SDL.h"
#endif

#include "ThreeDCubeGame.h"
#include "ThreeDCubeGameEnemy.h"
#include "MovementPosition.h"

//to use with hyper speed tile
bool speedStatus=false;

/** Constructor */
ThreeDCubeGameEnemy::ThreeDCubeGameEnemy(ThreeDCubeGame* pGame, 
							 int iMapX, int iMapY, 
							 int iCurrentDirection, int iType )
: DisplayableObject( pGame )
, m_iCurrentMapX(iMapX)
, m_iCurrentMapY(iMapY)
, m_iNextMapX(iMapX)
, m_iNextMapY(iMapY)
, m_iCurrentDirection(iCurrentDirection%4) // Ensure 0-3 range
, m_iType(iType)
{
	/* Store the original X and Y coordinates - to return to. */
	m_iOriginalX = iMapX;
	m_iOriginalY = iMapY;

	m_iStartDrawPosX = 3;
	m_iStartDrawPosY = 3;
	m_iDrawWidth = ThreeDCubeGame::BLOCK_SIZE*2;
	m_iDrawHeight = ThreeDCubeGame::BLOCK_SIZE*2;
	
	m_iCurrentScreenX = 0;
	m_iCurrentScreenY = 0;
	m_iPreviousScreenX = 0;
	m_iPreviousScreenY = 0;
	//below are types of different opponent colours
	switch( iType % 6 )
	{
	case 0:
		m_iColour = 0x000101;
		break;
	case 1:
		m_iColour = 0x010100;
		break;
	case 2:
		m_iColour = 0x000101;
		break;
	case 3:
		m_iColour = 0x000001;
		break;
	case 4:
		m_iColour = 0x000100;
		break;
	case 5:
		m_iColour = 0x010000;
		break;
	}

	// Set initial position based upon the map position
	SetMovementPosition( 0 );
}



/** Destructor */
ThreeDCubeGameEnemy::~ThreeDCubeGameEnemy()
{
}

/**
Draw the player object.
Just uses a coloured ball at the moment.
*/
void ThreeDCubeGameEnemy::Draw()
{
	ThreeDCubeGame* pGame = dynamic_cast<ThreeDCubeGame*>(m_pGame);
	int iColour = m_iColour;
	speedStatus=pGame->m_iHyperSpeed;
	
	//if the player is immune, the opponent colour changes to reflect that it is scared
	if (pGame->m_iImmunityStatus==true)
	{
		iColour=0xFFFF33;
	}

	// concentric circles for opponents
	int iRadiusSquared = (m_iDrawWidth/3) * (m_iDrawWidth/3);
	int iCentreX = m_iCurrentScreenX + m_iStartDrawPosX + m_iDrawWidth/2;
	int iCentreY = m_iCurrentScreenY + m_iStartDrawPosY + m_iDrawHeight/2;
	for ( int iX = m_iCurrentScreenX + m_iStartDrawPosX ; iX < (m_iCurrentScreenX + m_iStartDrawPosX + m_iDrawWidth) ; iX++ )
		for ( int iY = m_iCurrentScreenY + m_iStartDrawPosY ; iY < (m_iCurrentScreenY + m_iStartDrawPosY + m_iDrawHeight) ; iY++ )
			if ( ( (iX-iCentreX)*(iX-iCentreX) + (iY-iCentreY)*(iY-iCentreY) ) <= iRadiusSquared )
			{
				unsigned int uiColour = (0xB0 * ((iX-iCentreX)*(iX-iCentreX) + (iY-iCentreY)*(iY-iCentreY))) / iRadiusSquared;
				uiColour = 0xff - uiColour;
				GetGame()->SetScreenPixel( iX, iY, iColour * uiColour );
			}

	// Store the position at which the object was last drawn
	// This tells the system where to 'undraw' the object from
	StoreLastScreenPositionAndUpdateRect();
}


/**
Return true if tile can be entered by enemy.
*/
bool ThreeDCubeGameEnemy::CanEnter( int iMapX, int iMapY )
{
	//use dynamic casting to ensure some level of safety
	ThreeDCubeGame* pGame = dynamic_cast<ThreeDCubeGame*>(m_pGame);

	//if opponents freozen, then they cannot enter anytile
	//so they will be stuck in their current position
	if( pGame->m_iFreezeStatus==true )
	{
		return false;
	}
	else
	{
		switch( pGame->GetMapEntry( iMapX, iMapY ) )
		{
		case 'X': return false;break;//opponents cannot enter blank spots
		case 'S': return false;break;//opponents cannot enter safe spot
		case 'A': return true;break;
		case 'B': return true;break;
		case 'C': return true;break;
		case 'D': return true;break;
		case 'E': return true;break;
		case 'F': return true;break;
		case 'H': return true;break;
		case 'I': return true;break;
		case 'P': return true;break;		
		case 'L': return true;break;		
		case 'M': return true;break;
		}
	return false;
	}
}


/** Return true if creature can move in the specified direction */
bool ThreeDCubeGameEnemy::CanMoveInDirection( int iDirection )
{
	int iNewX = m_iCurrentMapX;
	int iNewY = m_iCurrentMapY;

	switch( iDirection )
	{
	case 0: // Left
		iNewX--;
		iNewY++;
		break;
	case 1: // Up
		iNewX--;
		iNewY--;
		break;
	case 2: // Right
		iNewX++;
		iNewY--;
		break;
	case 3: // Down
		iNewX++;
		iNewY++;
		break;
	}

	if ( iNewX < 0)
		return false;
	if ( iNewY < 0)
		return false;
	if ( iNewX >= ThreeDCubeGame::MAP_WIDTH )
		return false;
	if ( iNewY >= ThreeDCubeGame::MAP_HEIGHT )
		return false;

	return CanEnter( iNewX, iNewY );
}
			

/** Implement a move in the specified direction */
void ThreeDCubeGameEnemy::SetDirectionAndMove( int iDirection, int iTimeDelay )
{
	m_iCurrentDirection = iDirection;
	
	switch( iDirection )
	{
	case 0: // Left
		m_iNextMapX--;
		m_iNextMapY++;
		break;
	case 1: // Up
		m_iNextMapX--;
		m_iNextMapY--;
		break;
	case 2: // Right
		m_iNextMapX++;
		m_iNextMapY--;
		break;
	case 3: // Down
		m_iNextMapX++;
		m_iNextMapY++;
		break;
	}
	//to make enemy jumps unpredictable
	if( speedStatus == true )
		SetMovementPosition( 200+ rand()% 300 );
	else	
		SetMovementPosition( 300+ rand()% 400 );
}


/**
Handle the update action, moving the object and/or handling any game logic
*/
void ThreeDCubeGameEnemy::DoUpdate( int iCurrentTime )
{
	// Check for enemy catching the player
	CheckCollision();

	// Calculate the new position
	m_oMovement.Calculate(iCurrentTime);
	m_iCurrentScreenX = m_oMovement.GetX();
	m_iCurrentScreenY = m_oMovement.GetY();

	// If object is still moving between locations then work out the new location to move to
	if ( !m_oMovement.HasMovementFinished( iCurrentTime ) )
	{ // Nothing else to do - position has been calculated
	}
	else
	{
		// Store new position as current position
		m_iCurrentMapX = m_iNextMapX;
		m_iCurrentMapY = m_iNextMapY;

		// Check for direction changes

		switch ( rand()%16)
		{
		case 1: // Try clockwise turn then forwards, then anti-clockwise turn
			if ( CanMoveInDirection( ( m_iCurrentDirection + 1) %4 ) ) // Clockwise
				SetDirectionAndMove( ( m_iCurrentDirection + 1) %4, 300 + rand()%300 );
			else if ( CanMoveInDirection( m_iCurrentDirection ) ) // Forward
				SetDirectionAndMove( m_iCurrentDirection, 300 + rand()%100 );
			else if ( CanMoveInDirection( ( m_iCurrentDirection + 3) %4 ) ) // Anti-clockwise
				SetDirectionAndMove( ( m_iCurrentDirection + 3) %4, 300 + rand()%300 );
			else if ( CanMoveInDirection( ( m_iCurrentDirection + 2) %4 ) )
				SetDirectionAndMove( ( m_iCurrentDirection + 2) %4, 300 + rand()%300 );
			break;
		case 2: // Try anti-clockwise turn then forwards, then anti-clockwise turn
			if ( CanMoveInDirection( ( m_iCurrentDirection + 3) %4 ) ) // Anti-clockwise
				SetDirectionAndMove( ( m_iCurrentDirection + 3) %4, 300 + rand()%300 );
			else if ( CanMoveInDirection( m_iCurrentDirection ) ) // Forward
				SetDirectionAndMove( m_iCurrentDirection, 300 + rand()%100 );
			else if ( CanMoveInDirection( ( m_iCurrentDirection + 1) %4 ) ) // Clockwise
				SetDirectionAndMove( ( m_iCurrentDirection + 1) %4, 300 + rand()%300 );
			else if ( CanMoveInDirection( ( m_iCurrentDirection + 2) %4 ) )
				SetDirectionAndMove( ( m_iCurrentDirection + 2) %4, 300 + rand()%300 );
			break;
		case 3: // Forwards then turn if necessary
		case 4:
		case 5:
		case 6:
		case 7:
		case 8: 
		case 9:
			if ( CanMoveInDirection( m_iCurrentDirection ) ) // Forward
				SetDirectionAndMove( m_iCurrentDirection, 300 + rand()%100 );
			else if ( CanMoveInDirection( ( m_iCurrentDirection + 1) %4 ) ) // Clockwise
				SetDirectionAndMove( ( m_iCurrentDirection + 1) %4, 300 + rand()%300 );
			else if ( CanMoveInDirection( ( m_iCurrentDirection + 3) %4 ) ) // Anti-clockwise
				SetDirectionAndMove( ( m_iCurrentDirection + 3) %4, 300 + rand()%300 );
			else if ( CanMoveInDirection( ( m_iCurrentDirection + 2) %4 ) ) // Backwards - always works?
				SetDirectionAndMove( ( m_iCurrentDirection + 2) %4, 300 + rand()%300 );
			break;
		case 10: // Forwards then turn if necessary
		case 11:
		case 12:
		case 13:
		case 14:
		case 15:
		default: // incl. zero
			if ( CanMoveInDirection( m_iCurrentDirection ) ) // Forward
				SetDirectionAndMove( m_iCurrentDirection, 300 + rand()%100 );
			else if ( CanMoveInDirection( ( m_iCurrentDirection + 3) %4 ) ) // Anti-clockwise
				SetDirectionAndMove( ( m_iCurrentDirection + 3) %4, 300 + rand()%300 );
			else if ( CanMoveInDirection( ( m_iCurrentDirection + 1) %4 ) ) // Clockwise
				SetDirectionAndMove( ( m_iCurrentDirection + 1) %4, 300 + rand()%300 );
			else if ( CanMoveInDirection( ( m_iCurrentDirection + 2) %4 ) ) // Backwards - always works?
				SetDirectionAndMove( ( m_iCurrentDirection + 2) %4, 300 + rand()%300 );
			break;
		}
	}

	// Ensure that the object gets redrawn on the display, if something changed
	RedrawObjects();
}


/** Assumes that the current and next map coordinates have been set
This is the same as for a player object!
*/
void ThreeDCubeGameEnemy::SetMovementPosition( int iMoveDuration )
{
	int iCurrentTime = m_pGame->GetTime();
	// Set up the movement positions for the next movement
	int iX1 = ThreeDCubeGame::MAP_X_OFFSET + ThreeDCubeGame::BLOCK_SIZE * m_iCurrentMapX + POSITION_OFFSET_X;
	int iY1 = ThreeDCubeGame::MAP_Y_OFFSET + ThreeDCubeGame::BLOCK_SIZE * m_iCurrentMapY * 2 + POSITION_OFFSET_Y;
	int iX3 = ThreeDCubeGame::MAP_X_OFFSET + ThreeDCubeGame::BLOCK_SIZE * m_iNextMapX + POSITION_OFFSET_X;
	int iY3 = ThreeDCubeGame::MAP_Y_OFFSET + ThreeDCubeGame::BLOCK_SIZE * m_iNextMapY * 2 + POSITION_OFFSET_Y;
	int iX2 = (iX1 + iX3)/2;
	int iY2 = (iY1 + iY3)/2-40;

	m_oMovement.Setup(	iX1, iY1, iX2, iY2, iX3, iY3,
			iCurrentTime, iCurrentTime+iMoveDuration );
	// Calculate the new position for the current time
	m_oMovement.Calculate(iCurrentTime);
	m_iCurrentScreenX = m_oMovement.GetX();
	m_iCurrentScreenY = m_oMovement.GetY();
}


/** Check for collision between this char and enemy */
void ThreeDCubeGameEnemy::CheckCollision()
{
	//added by me
	ThreeDCubeGame* pGame = dynamic_cast<ThreeDCubeGame*>(m_pGame);

	DisplayableObject* pPlayer = m_pGame->GetDisplayableObject( 0/*Player*/ );

	int iXDiff = GetXCentre() - pPlayer->GetXCentre();
	int iYDiff = GetYCentre() - pPlayer->GetYCentre();
	
	//if you are immune, then ignore collision
	if ( (iXDiff*iXDiff + iYDiff*iYDiff) < (ThreeDCubeGame::BLOCK_SIZE * ThreeDCubeGame::BLOCK_SIZE ) && pGame->m_iImmunityStatus==false )
	{
		pGame->m_iLivesLeft--;
		pGame->m_iPowerTime=10000;
		pGame->m_iPowerStatus=false;
		pGame->m_iFreezeTime=10000;
		pGame->m_iFreezeStatus=false;
		pGame->m_iImmunityTime=10000;
		pGame->m_iImmunityStatus=false;
		pGame->m_iHyperSpeed=false;
		pGame->InitialiseObjects();	
		pGame->DrawScreen();
		pGame->pausetype=1;
		pGame->m_bPaused=true;
	}
}